#ifndef RANDMAP_H
#define RANDMAP_H

// stl
#include <iostream>
#include <unordered_map>
// raylib
#include <raylib.h>
#include <rlgl.h>
// maze
#include <mapbase.h>
#include <chunk.h>
#include <search/bfszx.h>
#include <generate/df_maze.h>
#include <generate/division_maze.h>

class RandMap
{
private:
    // chunk
    int max_chunk = 6;
    Coord<int> coord_chunck_center;
    std::unordered_map<Coord<int>, Chunk> chunks;
    // search
    std::vector<std::vector<Coord<int>>> path;
    int currentPath=0;
    Coord<int> coord_curser;
    Coord<int> search_offset;
    Coord<int> search_chunk_start;
    Coord<int> search_chunk_end;
    States::search search_state;
    std::thread* thread_search = nullptr;
    std::atomic<bool> search_interrupt{false};
    // render
    int block_size = 48;
    std::unordered_map<int, Texture2D> texture_blocks;
    bool isDevMode = true;
    bool isRestrictedMode = false;  // 受限时视角固定
    bool isRenderDepth = true; // 是否绘制深度暗示
    Coord<int> restrictChunkSize = {6, 6};
    // shader depth
    Shader shader_depth;
    int shader_depth_intensity_local;
    int shader_depth_direction_local;
    int shader_depth_diagDirection_local;
    float shader_depth_intensity = 0.3;
    Vector4 shader_depth_direction;
    Vector4 shader_depth_diagDirection;
    // test
    Coord<int> heroWorldPos;
    Coord<int> camoffsetbase;
public:
    //render
    static const int default_block_size = 48;
    Camera2D camera;
    
public:
    RandMap(std::unordered_map<std::string, Texture2D>& textures){
        setTextures(textures);

        camera.target = {0,0};
        camera.offset = {0,0};
        camera.rotation = 0.0f;
        camera.zoom = 1.0f;
        coord_chunck_center = {0,0};

        // render
        coord_curser = {0,0};

        // search
        search_offset = {0,0};
        search_chunk_start = {0,0};
        search_chunk_end = {0,0};
        search_state = States::search::stopped;

        // shader depth
        shader_depth = LoadShader(0, "assets/shaders/depth.frag");
        shader_depth_intensity_local = GetShaderLocation(shader_depth, "intensity");
        shader_depth_direction_local = GetShaderLocation(shader_depth, "direction");
        shader_depth_diagDirection_local = GetShaderLocation(shader_depth, "diagDirection");
    }

    void init(){
        //test
        heroWorldPos = {10,10};
        camoffsetbase = {0,0};
        // generateStructure({0,0},{40,40},0, df_maze);
        search({0,0},{18,18},0,bfszx);

        // std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        // for(int chunkoffsetX=-max_chunk/2; chunkoffsetX<max_chunk/2+1; chunkoffsetX++)
        //     for(int chunkoffsetY=-max_chunk/2; chunkoffsetY<max_chunk/2+1; chunkoffsetY++)
        //         getChunk(coord_chunck_center + Coord<int>{chunkoffsetX,chunkoffsetY});
    }

    void creatChunk(const Coord<int>& coord){
        Chunk chunk = Chunk(coord);
        chunks.emplace(coord,chunk);
    }

    int getBlock(int x, int y){
        Coord<int> chunkbasedcoord = getChunkBasedCoord(x,y);
        return getChunk(getChunkCoord(x,y)).getBlock(chunkbasedcoord.x,chunkbasedcoord.y);
    }

    void setBlock(int x, int y, int type){
        Coord<int> chunkbasedcoord = getChunkBasedCoord(x,y);
        getChunk(getChunkCoord(x,y)).setBlock(chunkbasedcoord.x,chunkbasedcoord.y,type);
        // 更新shader_depth
        Coord<int> chunkcoord = getChunkCoord(x,y);
        updateChunkTextureShaderDepth(getChunk(chunkcoord));
        if(getChunkCoord(x+1, y) == chunkcoord + Coord<int>{1, 0}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{1, 0}));
        if(getChunkCoord(x-1, y) == chunkcoord + Coord<int>{-1, 0}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{-1, 0}));
        if(getChunkCoord(x, y+1) == chunkcoord + Coord<int>{0, 1}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{0, 1}));
        if(getChunkCoord(x, y-1) == chunkcoord + Coord<int>{0, -1}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{0, -1}));
        if(getChunkCoord(x+1, y+1) == chunkcoord + Coord<int>{1, 1}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{1, 1}));
        if(getChunkCoord(x-1, y-1) == chunkcoord + Coord<int>{-1, -1}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{-1, -1}));
        if(getChunkCoord(x-1, y+1) == chunkcoord + Coord<int>{-1, 1}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{-1, 1}));
        if(getChunkCoord(x+1, y-1) == chunkcoord + Coord<int>{1, -1}) updateChunkTextureShaderDepth(getChunk(chunkcoord + Coord<int>{1, -1}));
    }

    Chunk& getChunk(const Coord<int>& coord){
        if (chunks.find(coord) == chunks.end()) {
            Chunk chunk(coord);
            chunks.emplace(coord, chunk);
            // 更新深度暗示
            // updateChunkTextureShaderDepth(chunk);
            std::cout << "zxionf : Generated Chunk at (" << coord.x << " , " << coord.y << ")" << std::endl;
        }
        return chunks.at(coord);
    }

    Coord<int> getChunkBasedCoord(int x, int y){
        Coord<int> coord;
        if(x >= 0)
            coord.x = x % Chunk::chunksize;
        else
            coord.x = (x % Chunk::chunksize + Chunk::chunksize) % Chunk::chunksize;
        if(y >= 0)
            coord.y = y % Chunk::chunksize;
        else
            coord.y = (y % Chunk::chunksize + Chunk::chunksize) % Chunk::chunksize;
        return coord;
    }

    Coord<int> getChunkCoord(int x, int y){
        Coord<int> chunkCoord;
        if(x >= 0)
            chunkCoord.x = x / Chunk::chunksize;
        else
            chunkCoord.x = (x+1) / Chunk::chunksize - 1;
        if(y >= 0)
            chunkCoord.y = y / Chunk::chunksize;
        else
            chunkCoord.y = (y+1) / Chunk::chunksize - 1;
        return chunkCoord;
    }

    void render(){
        // control camera Pos
        if (IsKeyDown(KEY_RIGHT)) camoffsetbase.x ++;
        if (IsKeyDown(KEY_LEFT)) camoffsetbase.x --;
        if (IsKeyDown(KEY_UP)) camoffsetbase.y --;
        if (IsKeyDown(KEY_DOWN)) camoffsetbase.y ++;

        // control camera zoom
        if(IsKeyDown(KEY_Z)) camera.zoom -= 0.05;
        if(IsKeyDown(KEY_X)) camera.zoom += 0.05;

        if(IsKeyPressed(KEY_O)) if(max_chunk-2>-1)max_chunk-=2;
        if(IsKeyPressed(KEY_P)) max_chunk+=2;

        // control current path
        if(IsKeyPressed(KEY_E)){
            // if(currentPath == path.size()) currentPath=0;
            if(currentPath < path.size()) currentPath=(currentPath+1)%path.size();
        }

        // test
        // control hero Pos
        if (IsKeyDown(KEY_D)) heroWorldPos.x ++;
        if (IsKeyDown(KEY_A)) heroWorldPos.x --;
        if (IsKeyDown(KEY_W)) heroWorldPos.y --;
        if (IsKeyDown(KEY_S)) heroWorldPos.y ++;

        // Restricted Mode
        if(isRestrictedMode)
        {
            coord_chunck_center.x = -1;
            coord_chunck_center.y = -1;
            camera.offset.x = camoffsetbase.x + default_block_size;
            camera.offset.y = camoffsetbase.y + default_block_size;
            camera.target.x = 0;
            camera.target.y = 0;
        }
        else
        {
            coord_chunck_center.x = heroWorldPos.x/Chunk::chunksize/default_block_size;
            coord_chunck_center.y = heroWorldPos.y/Chunk::chunksize/default_block_size;
            camera.offset.x = camoffsetbase.x + Chunk::chunksize*default_block_size*2;
            camera.offset.y = camoffsetbase.y + Chunk::chunksize*default_block_size*2;
            camera.target.x = heroWorldPos.x;
            camera.target.y = heroWorldPos.y;
        }

        
        // 绘制地块
        if(isRestrictedMode)
        {
            for(int chunkoffsetX=0; chunkoffsetX<restrictChunkSize.x; chunkoffsetX++)
                for(int chunkoffsetY=0; chunkoffsetY<restrictChunkSize.y; chunkoffsetY++)
                {
                    BeginMode2D(camera);
                    Chunk& chunk = getChunk(coord_chunck_center + Coord<int>{chunkoffsetX,chunkoffsetY});
                    for(int i=0; i<Chunk::chunksize; i++)
                        for(int j=0; j<Chunk::chunksize; j++)
                        {
                            DrawTextureEx(texture_blocks[chunk.getBlock(i,j)],Vector2Add(Vector2{(float)i*default_block_size,(float)j*default_block_size},Vector2Scale(chunk.getCoordV(),Chunk::chunksize*default_block_size)),0,default_block_size/block_size,WHITE);
                        }
                    // 绘制区块范围
                    if(isDevMode)DrawRectangleLines(chunk.getCoordV().x*Chunk::chunksize*default_block_size,
                                        chunk.getCoordV().y*Chunk::chunksize*default_block_size,
                                        Chunk::chunksize*default_block_size,
                                        Chunk::chunksize*default_block_size,GREEN);
                    if(isDevMode)DrawText(TextFormat(("%d , %d"), chunk.getCoord().x, chunk.getCoord().y), chunk.getCoordV().x*Chunk::chunksize*default_block_size,
                                        chunk.getCoordV().y*Chunk::chunksize*default_block_size, 16, GREEN);
                    EndMode2D();
                    // 绘制深度暗示
                    // updateChunkTextureShaderDepth(chunk);
                    BeginBlendMode(BLEND_MULTIPLIED);
                    BeginMode2D(camera);
                    if(isRenderDepth)DrawTexture(chunk.texture_shader_depth.texture,chunk.getCoordV().x*Chunk::chunksize*default_block_size,chunk.getCoordV().y*Chunk::chunksize*default_block_size,WHITE);
                    EndMode2D();
                    EndBlendMode();
                }
        }
        else
        {
            for(int chunkoffsetX=-max_chunk/2; chunkoffsetX<max_chunk/2+1; chunkoffsetX++)
                for(int chunkoffsetY=-max_chunk/2; chunkoffsetY<max_chunk/2+1; chunkoffsetY++)
                {
                    BeginMode2D(camera);
                    Chunk& chunk = getChunk(coord_chunck_center + Coord<int>{chunkoffsetX,chunkoffsetY});
                    for(int i=0; i<Chunk::chunksize; i++)
                        for(int j=0; j<Chunk::chunksize; j++)
                        {
                            DrawTextureEx(texture_blocks[chunk.getBlock(i,j)],Vector2Add(Vector2{(float)i*default_block_size,(float)j*default_block_size},Vector2Scale(chunk.getCoordV(),Chunk::chunksize*default_block_size)),0,default_block_size/block_size,WHITE);
                        }
                    // 绘制区块范围
                    if(isDevMode)DrawRectangleLines(chunk.getCoordV().x*Chunk::chunksize*default_block_size,
                                        chunk.getCoordV().y*Chunk::chunksize*default_block_size,
                                        Chunk::chunksize*default_block_size,
                                        Chunk::chunksize*default_block_size,GREEN);
                    if(isDevMode)DrawText(TextFormat(("%d , %d"), chunk.getCoord().x, chunk.getCoord().y), chunk.getCoordV().x*Chunk::chunksize*default_block_size,
                                        chunk.getCoordV().y*Chunk::chunksize*default_block_size, 16, GREEN);
                    // 绘制深度暗示
                    BeginBlendMode(BLEND_MULTIPLIED);
                    BeginMode2D(camera);
                    if(isRenderDepth)DrawTexture(chunk.texture_shader_depth.texture,chunk.getCoordV().x*Chunk::chunksize*default_block_size,chunk.getCoordV().y*Chunk::chunksize*default_block_size,WHITE);
                    EndMode2D();
                    EndBlendMode();
                }
        }
        BeginMode2D(camera);
        // 路径
        if(!path.empty())
            for(int i=0; i<path[currentPath].size()-1; i++)
                // DrawCircle(path[currentPath][i].first*48+24,path[currentPath][i].second*48+24,12,RED);
                DrawLineEx({(float)(path[currentPath][i].x+search_offset.x)*48+24,(float)(path[currentPath][i].y+search_offset.y)*48+24},
                    {(float)(path[currentPath][i+1].x+search_offset.x)*48+24,(float)(path[currentPath][i+1].y+search_offset.y)*48+24},
                    4,RED);
        // heroPos
        DrawCircle(heroWorldPos.x,heroWorldPos.y,5,RED);
        // curserblock
        float x = (GetMouseX()/camera.zoom -camera.offset.x/camera.zoom +camera.target.x) / 48;
        float y = (GetMouseY()/camera.zoom -camera.offset.y/camera.zoom +camera.target.y) / 48;
        coord_curser.x = x>=0?(int)x:x>-1?-1:(int)x-1;
        coord_curser.y = y>=0?(int)y:y>-1?-1:(int)y-1;
        DrawRectangleLinesEx({(float)coord_curser.x*48,(float)coord_curser.y*48,default_block_size,default_block_size},4,RED);
        // 哪些区块参与了搜索
        if(isDevMode)DrawRectangleLinesEx({(float)search_chunk_start.x*Chunk::chunksize*default_block_size,
                    (float)search_chunk_start.y*Chunk::chunksize*default_block_size,
                    (float)(search_chunk_end.x-search_chunk_start.x+1)*Chunk::chunksize*default_block_size,
                    (float)(search_chunk_end.y-search_chunk_start.y+1)*Chunk::chunksize*default_block_size},2,PURPLE);
        EndMode2D();
        
    }

    void updateBlockDepthInfo(int x, int y){
        // 正交方向
        float left=0,right=0,up=0,down=0;
        if(getBlock(x,y) == Blocks::value::wall){
            shader_depth_direction = {0,0,0,0};
            return;
        }
        if(getBlock(x-1,y) == Blocks::value::wall) left = 1;
        if(getBlock(x+1,y) == Blocks::value::wall) right=1;
        if(getBlock(x,y-1) == Blocks::value::wall) up=1;
        if(getBlock(x,y+1) == Blocks::value::wall) down=1;

        shader_depth_direction={left,right,up,down};

        // 斜角方向
        float leftup=0, rightup=0, leftdown=0, rightdown=0;
        if(getBlock(x-1,y-1) == Blocks::value::wall) leftup = 1;
        if(getBlock(x+1,y-1) == Blocks::value::wall) rightup=1;
        if(getBlock(x-1,y+1) == Blocks::value::wall) leftdown=1;
        if(getBlock(x+1,y+1) == Blocks::value::wall) rightdown=1;
        shader_depth_diagDirection={leftup,rightup,leftdown,rightdown};
    }

    void updateChunkTextureShaderDepth(Chunk& chunk){
        for(int i=0; i<Chunk::chunksize; i++)
            for(int j=0; j<Chunk::chunksize; j++)
            {
                updateBlockDepthInfo(chunk.getCoord().x*Chunk::chunksize + i, chunk.getCoord().y*Chunk::chunksize + j);
                BeginTextureMode(chunk.texture_shader_depth);
                BeginShaderMode(shader_depth);
                    float me = getBlock(chunk.getCoord().x*Chunk::chunksize + i, chunk.getCoord().y*Chunk::chunksize + j) == Blocks::value::wall;
                    SetShaderValue(shader_depth, GetShaderLocation(shader_depth, "me"), &me, SHADER_UNIFORM_FLOAT);
                    SetShaderValue(shader_depth, shader_depth_intensity_local, &shader_depth_intensity, SHADER_UNIFORM_FLOAT);
                    SetShaderValue(shader_depth, shader_depth_direction_local, &shader_depth_direction, SHADER_UNIFORM_VEC4);
                    SetShaderValue(shader_depth, shader_depth_diagDirection_local, &shader_depth_diagDirection, SHADER_UNIFORM_VEC4);
                    DrawTextureEx(texture_blocks[chunk.getBlock(i,j)],Vector2{(float)i*default_block_size,(float)(Chunk::chunksize-j-1)*default_block_size},0,default_block_size/block_size,WHITE);
                EndShaderMode();
                EndTextureMode();
            }
    }

    // 获取部分地图
    std::vector<std::vector<int>> getSplitedMap(Coord<int> startChunk, Coord<int> endChunk){
        Coord<int> size = endChunk - startChunk + Coord<int>{1,1};
        std::vector<std::vector<int>> map = {(long long unsigned int)size.x*Chunk::chunksize,std::vector<int>((long long unsigned int)size.y*Chunk::chunksize, Blocks::wall)};
        for(int i=startChunk.x; i<=endChunk.x; i++)
            for(int j=startChunk.y; j<=endChunk.y; j++)
            {
                Chunk& chunk = getChunk({i,j});
                for(int ii=0;ii<Chunk::chunksize;ii++)
                    for(int jj=0;jj<Chunk::chunksize;jj++)
                        map[(i-startChunk.x)*Chunk::chunksize+ii][(j-startChunk.y)*Chunk::chunksize+jj] = chunk.getBlock(ii,jj);
            }
        return map;
    }

    // void search(std::vector<std::vector<Coord<int>>> (*algo)(std::vector<std::vector<int>>,Coord<int>,Coord<int>,const std::atomic<bool>& interrupt)){
    //     Coord<int> globalStartCoord = {5,5};
    //     Coord<int> globalEndCoord = {14,14};
    //     Coord<int> splitChunkStartCoord = {1,1};
    //     Coord<int> splitChunkEndCoord = {3,3};
    //     std::vector<std::vector<int>> map = getSplitedMap(splitChunkStartCoord,splitChunkEndCoord);
    //     search_offset = splitChunkStartCoord*Coord<int>{4,4};
    //     path = algo(map,globalStartCoord-search_offset,globalEndCoord-search_offset,NULL);
    // }

    // 起、终点全局坐标，起、终点切片区块坐标，通用算法
    void search(Coord<int> globalStartCoord,
                Coord<int> globalEndCoord,
                Coord<int> splitChunkStartCoord,
                Coord<int> splitChunkEndCoord,
                std::vector<std::vector<Coord<int>>> (*algo)(std::vector<std::vector<int>>,Coord<int>,Coord<int>,const std::atomic<bool>& interrupt)
    ){
        search_chunk_start = splitChunkStartCoord;
        search_chunk_end = splitChunkEndCoord;
        std::vector<std::vector<int>> map = getSplitedMap(splitChunkStartCoord,splitChunkEndCoord);
        search_offset = splitChunkStartCoord*Coord<int>{4,4};
        // path = algo(map,globalStartCoord-search_offset,globalEndCoord-search_offset,NULL);
        search_core(algo,map,globalStartCoord-search_offset,globalEndCoord-search_offset);
    }

    void search(Coord<int> globalStartCoord,
                Coord<int> globalEndCoord,
                int chunkOffest,
                std::vector<std::vector<Coord<int>>> (*algo)(std::vector<std::vector<int>>,Coord<int>,Coord<int>,const std::atomic<bool>& interrupt)
    ){
        search_chunk_start = getChunkCoord(globalStartCoord.x,globalStartCoord.y)-Coord<int>{chunkOffest,chunkOffest};
        search_chunk_end = getChunkCoord(globalEndCoord.x,globalEndCoord.y)+Coord<int>{chunkOffest,chunkOffest};
        std::vector<std::vector<int>> map = getSplitedMap(search_chunk_start, search_chunk_end);
        search_offset = (getChunkCoord(globalStartCoord.x,globalStartCoord.y)-Coord<int>{chunkOffest,chunkOffest})*Coord<int>{4,4};
        // path = algo(map,globalStartCoord-search_offset,globalEndCoord-search_offset,NULL);
        search_core(algo,map,globalStartCoord-search_offset,globalEndCoord-search_offset);
    }

    void search_core(std::vector<std::vector<Coord<int>>> (*algo)(std::vector<std::vector<int>>,Coord<int>,Coord<int>,const std::atomic<bool>& interrupt),std::vector<std::vector<int>> map,Coord<int> startPoint,Coord<int> endPoint){
        // if(block_quantities.start != 1 || block_quantities.end != 1)
        // {
        //     std::cout << "zxionf: TileMap block_quantities.start != 1 || block_quantities.end != 1" << std::endl;
        //     return false;
        // }
        // if(isInited)for(int i=0; i<width; i++)
        //     for(int j=0; j<height; j++)
        //     {
        //         if(map[i][j]==Blocks::value::start) startPoint = {i ,j};
        //         else if(map[i][j]==Blocks::value::end) endPoint = {i, j};
        //     }
        currentPath = 0;
        search_interrupt = true;
        stop_search();
        search_interrupt = false;
        search_state = States::search::searching;
        thread_search = new std::thread([this, algo, map, startPoint, endPoint](){
            try {
                path = algo(map,startPoint,endPoint,search_interrupt);
                search_state = States::search::stopped;
            } catch (const std::runtime_error& e) {
                std::cout << "zxionf:Algorithm was interrupted: " << e.what() << std::endl;
            } catch (...) {
                std::cout << "zxionf:Algorithm encountered an error" << std::endl;
            }
        });
    }

    void stop_search(){
        if (thread_search!=nullptr && thread_search->joinable()) {
            thread_search->join();
            delete thread_search;
            thread_search = nullptr;
        }
    }

    void  generateStructure(Coord<int> globalCoord, Coord<int> size, int flag, std::vector<std::vector<int>> (*algo)(Coord<int>)){
        if(size.x<2 || size.y<2) return;
        std::vector<std::vector<int>> structure = algo(size);
        for(int i=0; i<size.x; i++)
            for(int j=0; j<size.x; j++)
            {
                Coord<int> chunkbasedcoord = getChunkBasedCoord(globalCoord.x+i,globalCoord.y+j);
                getChunk(getChunkCoord(globalCoord.x+i,globalCoord.y+j)).setBlock(chunkbasedcoord.x,chunkbasedcoord.y,structure[i][j]);
            }
        Coord<int> chunkstart = getChunkCoord(globalCoord.x, globalCoord.y);
        Coord<int> chunkend = getChunkCoord(globalCoord.x + size.x, globalCoord.y + size.y);
        for(int i = 0; i < chunkend.x-chunkstart.x; i++)
            for(int j = 0; j < chunkend.y-chunkstart.y; j++)
                updateChunkTextureShaderDepth(getChunk(chunkstart+Coord<int>{i,j}));
    }

    void drawInfo(int x, int y, int fontSize, Color color){
        DrawText(TextFormat("CurserAtBlock : %d , %d", coord_curser.x,coord_curser.y), x, y+fontSize*0, fontSize, color);
        DrawText(TextFormat("CameraZoom : %f", camera.zoom), x, y+fontSize*1, fontSize, color);
        DrawText(TextFormat("TotalPath : %d", path.size()), x, y+fontSize*2, fontSize, color);
        DrawText(TextFormat("CurrentPathID : %d", currentPath), x, y+fontSize*3, fontSize, color);
        DrawText(TextFormat("SearchChunkStart : %d , %d", search_chunk_start.x,search_chunk_start.y), x, y+fontSize*4, fontSize, color);
        DrawText(TextFormat("SearchChunkEnd : %d , %d", search_chunk_end.x,search_chunk_end.y), x, y+fontSize*5, fontSize, color);
        DrawText(TextFormat("SearchOffset : %d , %d", search_offset.x,search_offset.y), x, y+fontSize*6, fontSize, color);
        DrawText(TextFormat("SearchState : %s", search_state==States::search::stopped?"stopoed":"searching"), x, y+fontSize*7, fontSize, color);
    }

    void setDevMode(bool mode){
        isDevMode = mode;
    }

    bool getDevMode(){
        return isDevMode;
    }

    void setRestictMode(bool mode){
        isRestrictedMode = mode;
    }

    bool getRestrictMode(){
        return isRestrictedMode;
    }

    bool getSearchStopped(){
        return search_state == States::search::stopped;
    }

    void setTextures(std::unordered_map<std::string, Texture2D>& textures){
        block_size = textures["end"].width;
        texture_blocks.emplace(-2,textures["end"]);
        texture_blocks.emplace(-1,textures["start"]);
        texture_blocks.emplace(0,textures["floor"]);
        texture_blocks.emplace(1,textures["wall"]);
        texture_blocks.emplace(2,textures["grass"]);
        texture_blocks.emplace(3,textures["lava"]);
    }
};

#endif